#include "lua.hpp"
#include <iostream>
#include <vector>
#include <boost/tokenizer.hpp>
#include <string>
using namespace std;
using namespace boost;


const string yinHao("\"");
static void spilitYinHao(string var ,size_t found,vector<string> &myToken);

// first  sting to be spilit to token. 
// spiliter that will not be trade as a token.Can be omitted -> default is  " \n\r\t|"
// spiliter that will be trade as a token.Can be omitted-> default is  "(){}$"
extern "C" int luaNativeToolString2Token(lua_State *L)
{
	const int n = lua_gettop(L);
	if ( 0 == n )
	{
		lua_pushnil(L);
		return -1;
	}
	if (!lua_isstring(L, 1))
	{
		lua_pushnil(L);
		return -1;
	}
	const char *sourcString = lua_tostring(L,1);

	const char *spilitNoKeep = NULL;
	if( 2 <= n )
	{
		if (!lua_isstring(L, 2))
		{
			lua_pushnil(L);
			return -1;
		}
		spilitNoKeep = lua_tostring(L,2);
	}
	const char *spilitKeep = NULL;
	if( 3 <= n )
	{
		if (!lua_isstring(L, 3))
		{
			lua_pushnil(L);
			return -1;
		}
		spilitKeep = lua_tostring(L,3);
	}
	if ( NULL == spilitNoKeep )
	{
		spilitNoKeep = " \n\r\t|";
	}
	if ( NULL == spilitKeep )
	{
		spilitKeep = "(){}$&";
	}
	
	lua_newtable (L);
	int index = 1;
	
 	std::string str(sourcString);
    typedef boost::tokenizer<boost::char_separator<char> > 
        tokenizer;
    boost::char_separator<char> sep(spilitNoKeep, spilitKeep);
    tokenizer tokens(str, sep);
	vector<string> myToken;
    for (tokenizer::iterator tok_iter = tokens.begin();tok_iter != tokens.end(); ++tok_iter)
	{
		string var(*tok_iter);
		size_t found = var.find(yinHao);
		if ( string::npos == found )
		{
			myToken.push_back(var);
		}
		else
		{
			spilitYinHao(var,found,myToken);
		}
	}    
   for (vector<string>::iterator iter = myToken.begin();iter != myToken.end(); ++iter)
	{
		const char *value = iter->c_str();
		lua_pushnumber(L, index++);
		lua_pushstring(L, value);
		lua_settable(L, -3 );
	}    
	return 1;
}
// first-> Token sting to be spilit to command 
extern "C" int luaNativeToolToken2Lex(lua_State *L)
{
	const int n = lua_gettop(L);
	if ( 1 != n )
	{
		lua_pushnil(L);
		return -1;
	}
	if (!lua_isstring(L, 1))
	{
		lua_pushnil(L);
		return -1;
	}
	const char *sourcString = lua_tostring(L,1);
	
	
 	std::string str(sourcString);
    typedef tokenizer<char_separator<char> > tokenizer;
    char_separator<char> sep("", "()");
    tokenizer tokens(str, sep);
	const string constStrLeft("(");
	const string constStrRight(")");
	vector<string> commandList;
	string catCommand("");
    for (tokenizer::iterator tok_iter = tokens.begin();tok_iter != tokens.end(); ++tok_iter)
	{
		catCommand += *tok_iter;
		if ( constStrRight == *tok_iter )
		{
			commandList.push_back(catCommand);
			catCommand = "";
		}
	}
	if( "" != catCommand)
	{
		lua_pushnil(L);
		return -1;
	}

	lua_newtable (L);
	int index = 1;
	for(int i = 0;i < commandList.size();i++)
	{
		const char *value = commandList.at(i).c_str();
		lua_pushnumber(L, index++);
		lua_pushstring(L, value);
		lua_settable(L, -3 );
//		cout<<value<<endl;
	}
	commandList.clear();
	return 1;
}
// first-> Token sting to be spilit to command 
extern "C" int luaNativeToolStringReplace(lua_State *L)
{
	const int n = lua_gettop(L);
	if ( 3 != n )
	{
		lua_pushnil(L);
		return -1;
	}
	if (!lua_isstring(L, 1))
	{
		lua_pushnil(L);
		return -1;
	}
	const char *sourcString = lua_tostring(L,1);

	if (!lua_isstring(L, 2))
	{
		lua_pushnil(L);
		return -1;
	}
	const char *toBeReplaced = lua_tostring(L,2);

	if (!lua_isstring(L, 3))
	{
		lua_pushnil(L);
		return -1;
	}
	const char *replace = lua_tostring(L,3);
	int size = strlen(sourcString);
	char *ret = new char[size +1];
	memset(ret,0,size +1);
	memcpy(ret,sourcString,size);
	while ( size > 0 )
	{
		if ( *toBeReplaced == ret[--size] )
		{
			ret[size]=*replace; 
		}
	}
	lua_pushstring(L, ret);
	return 1;
}


static void spilitYinHao(string var ,size_t found,vector<string> &myToken)
{
	string before = var.substr(0,found);
	if ( false == before.empty())
	{
		myToken.push_back(before);
	}
	myToken.push_back(yinHao);
	string after = var.substr(found+1);
	if ( false == after.empty())
	{
		size_t found2 = after.find(yinHao);
		if ( string::npos == found2 )
		{
			myToken.push_back(after);
		}
		else
		{
			spilitYinHao(after,found2,myToken);
		}
//		myToken.push_back(after);
	}
//	cout<<var<<"at ["<<found<<"]"<<"before["<<before<<"]"<<"after["<<after<<"]"<<endl;
}
